package com.zxy.supplier_system.server.utils

import java.time.Duration
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit

class Storage<K : Any, V>(private val defaultExpiation: Duration? = null) : MutableMap<K, V> {

    private val map = ConcurrentHashMap<K, Value<V>>()

    private inner class Value<V>(key: K, val value: V, duration: Duration?) {

        val expiationTime = duration?.let {
            System.currentTimeMillis() + duration.toMillis()
        }

        private val cancelDestroyTimerFunction = {
            // Cancel the timer of destroy task
            this.destroyTimer?.cancel()
            // Remove from storage
            this@Storage.remove(key)
        }

        // Time to destroy
        private val destroyTimer: Timer? = duration?.let {
            val timer = Timer()
            timer.schedule(object : TimerTask() {
                override fun run() {
                    remove()
                }
            }, duration.toMillis())
            timer
        }

        fun remove() {
            this.cancelDestroyTimerFunction()
        }

    }

    override fun containsKey(key: K): Boolean = this.map.containsKey(key)

    override fun containsValue(value: V): Boolean = this.map.values.stream().anyMatch { it.value == value }

    override fun get(key: K): V? = this.map[key]?.value

    override fun isEmpty(): Boolean = this.map.isEmpty()

    override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
        get() = this.map.mapValues { it.value.value }.toMutableMap().entries

    override val keys: MutableSet<K>
        get() = this.map.keys
    override val values: MutableCollection<V>
        get() = TODO(
            "not implemented"
        ) //To change initializer of created properties use File | Settings | File Templates.

    override fun clear() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun put(key: K, value: V): V? {
        this.map[key] = Value(key, value, this.defaultExpiation)
        return value
    }

    fun put(key: K, value: V, expiation: Duration? = this.defaultExpiation): V {
        this.map[key] = Value(key, value, expiation)
        return value
    }

    override fun putAll(from: Map<out K, V>) {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun remove(key: K): V? {
        return this.map.remove(key)?.value
    }

    fun getExpire(key: K, unit: TimeUnit): Long? {
        val value = this.map[key]
        return value?.expiationTime?.let {
            unit.convert(value.expiationTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS)
        }
    }

    override val size: Int
        get() = TODO(
            "not implemented"
        ) //To change initializer of created properties use File | Settings | File Templates.


}